import BaseMiddleware from './BaseMiddleware.js';
import ResponseFormatter from '../utils/ResponseFormatter.js';
import { config } from '../config.js';

/**
 * 验证中间件 - 统一处理API请求的数据验证
 */
export class ValidationMiddleware extends BaseMiddleware {
    constructor(options = {}) {
        super({
            priority: 80, // 在认证和授权之后执行
            sanitize: true, // 是否自动清理数据
            strictMode: false, // 严格模式，不允许额外字段
            ...options
        });
        
        // 预定义验证规则
        this.commonRules = {
            email: {
                type: 'string',
                pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
                maxLength: 255
            },
            password: {
                type: 'string',
                minLength: 6,
                maxLength: 128,
                pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/
            },
            phone: {
                type: 'string',
                pattern: /^1[3-9]\d{9}$/
            },
            url: {
                type: 'string',
                pattern: /^https?:\/\/.+/
            },
            positiveInteger: {
                type: 'number',
                min: 1,
                integer: true
            },
            nonNegativeInteger: {
                type: 'number',
                min: 0,
                integer: true
            }
        };
    }

    /**
     * 执行验证逻辑
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     * @param {Function} next - Express next函数
     */
    async execute(req, res, next) {
        // 如果没有验证规则，直接通过
        if (!req.validationRules) {
            return next();
        }

        try {
            // 执行验证
            const validationResult = await this.validateRequest(req, req.validationRules);
            
            if (!validationResult.isValid) {
                this.logValidationFailure(req, validationResult.errors);
                return ResponseFormatter.validationError(res, validationResult.errors, 'Validation failed');
            }

            // 如果启用了数据清理，更新请求数据
            if (this.options.sanitize && validationResult.sanitizedData) {
                req.body = validationResult.sanitizedData.body || req.body;
                req.query = validationResult.sanitizedData.query || req.query;
                req.params = validationResult.sanitizedData.params || req.params;
            }

            // 记录验证成功
            this.logValidationSuccess(req);
            
            next();
        } catch (error) {
            console.error('[ValidationMiddleware] Validation error:', error);
            return ResponseFormatter.error(res, 'Validation processing failed', 500);
        }
    }

    /**
     * 验证请求数据
     * @param {Request} req - Express请求对象
     * @param {Object} rules - 验证规则
     * @returns {Object} 验证结果
     */
    async validateRequest(req, rules) {
        const errors = [];
        const sanitizedData = {
            body: {},
            query: {},
            params: {}
        };

        // 验证请求体
        if (rules.body) {
            const bodyResult = await this.validateData(req.body || {}, rules.body, 'body');
            errors.push(...bodyResult.errors);
            sanitizedData.body = bodyResult.sanitizedData;
        }

        // 验证查询参数
        if (rules.query) {
            const queryResult = await this.validateData(req.query || {}, rules.query, 'query');
            errors.push(...queryResult.errors);
            sanitizedData.query = queryResult.sanitizedData;
        }

        // 验证路径参数
        if (rules.params) {
            const paramsResult = await this.validateData(req.params || {}, rules.params, 'params');
            errors.push(...paramsResult.errors);
            sanitizedData.params = paramsResult.sanitizedData;
        }

        // 验证请求头
        if (rules.headers) {
            const headersResult = await this.validateData(req.headers || {}, rules.headers, 'headers');
            errors.push(...headersResult.errors);
        }

        return {
            isValid: errors.length === 0,
            errors,
            sanitizedData: this.options.sanitize ? sanitizedData : null
        };
    }

    /**
     * 验证数据对象
     * @param {Object} data - 要验证的数据
     * @param {Object} rules - 验证规则
     * @param {string} context - 验证上下文
     * @returns {Object} 验证结果
     */
    async validateData(data, rules, context = 'data') {
        const errors = [];
        const sanitizedData = {};
        const processedFields = new Set();

        // 验证每个字段
        for (const [field, rule] of Object.entries(rules)) {
            processedFields.add(field);
            const value = data[field];
            const fieldPath = `${context}.${field}`;

            try {
                const fieldResult = await this.validateField(value, rule, fieldPath);
                
                if (!fieldResult.isValid) {
                    errors.push(...fieldResult.errors);
                } else if (this.options.sanitize) {
                    sanitizedData[field] = fieldResult.sanitizedValue;
                }
            } catch (error) {
                errors.push(`${fieldPath}: Validation processing error`);
            }
        }

        // 严格模式检查额外字段
        if (this.options.strictMode) {
            for (const field of Object.keys(data)) {
                if (!processedFields.has(field)) {
                    errors.push(`${context}.${field}: Unexpected field`);
                }
            }
        } else if (this.options.sanitize) {
            // 非严格模式下保留未验证的字段
            for (const [field, value] of Object.entries(data)) {
                if (!processedFields.has(field)) {
                    sanitizedData[field] = value;
                }
            }
        }

        return {
            isValid: errors.length === 0,
            errors,
            sanitizedData
        };
    }

    /**
     * 验证单个字段
     * @param {*} value - 字段值
     * @param {Object} rule - 验证规则
     * @param {string} fieldPath - 字段路径
     * @returns {Object} 验证结果
     */
    async validateField(value, rule, fieldPath) {
        const errors = [];
        let sanitizedValue = value;

        // 处理预定义规则
        if (typeof rule === 'string' && this.commonRules[rule]) {
            rule = this.commonRules[rule];
        }

        // 处理规则数组（OR逻辑）
        if (Array.isArray(rule)) {
            let hasValidRule = false;
            const allErrors = [];
            
            for (const subRule of rule) {
                const subResult = await this.validateField(value, subRule, fieldPath);
                if (subResult.isValid) {
                    hasValidRule = true;
                    sanitizedValue = subResult.sanitizedValue;
                    break;
                } else {
                    allErrors.push(...subResult.errors);
                }
            }
            
            if (!hasValidRule) {
                errors.push(...allErrors);
            }
            
            return { isValid: hasValidRule, errors, sanitizedValue };
        }

        // 必填验证
        if (rule.required && (value === undefined || value === null || value === '')) {
            errors.push(`${fieldPath}: Field is required`);
            return { isValid: false, errors, sanitizedValue };
        }

        // 如果字段不存在且不是必填，跳过其他验证
        if (value === undefined || value === null) {
            return { isValid: true, errors: [], sanitizedValue: rule.default || value };
        }

        // 类型转换和验证
        const typeResult = this.validateAndConvertType(value, rule, fieldPath);
        if (!typeResult.isValid) {
            errors.push(...typeResult.errors);
            return { isValid: false, errors, sanitizedValue };
        }
        sanitizedValue = typeResult.convertedValue;

        // 长度验证
        if (rule.minLength !== undefined && sanitizedValue.length < rule.minLength) {
            errors.push(`${fieldPath}: Must be at least ${rule.minLength} characters long`);
        }

        if (rule.maxLength !== undefined && sanitizedValue.length > rule.maxLength) {
            errors.push(`${fieldPath}: Must be no more than ${rule.maxLength} characters long`);
        }

        // 数值范围验证
        if (typeof sanitizedValue === 'number') {
            if (rule.min !== undefined && sanitizedValue < rule.min) {
                errors.push(`${fieldPath}: Must be at least ${rule.min}`);
            }
            
            if (rule.max !== undefined && sanitizedValue > rule.max) {
                errors.push(`${fieldPath}: Must be no more than ${rule.max}`);
            }
            
            if (rule.integer && !Number.isInteger(sanitizedValue)) {
                errors.push(`${fieldPath}: Must be an integer`);
            }
        }

        // 正则表达式验证
        if (rule.pattern && typeof sanitizedValue === 'string' && !rule.pattern.test(sanitizedValue)) {
            errors.push(`${fieldPath}: Format is invalid`);
        }

        // 枚举值验证
        if (rule.enum && !rule.enum.includes(sanitizedValue)) {
            errors.push(`${fieldPath}: Must be one of: ${rule.enum.join(', ')}`);
        }

        // 数组验证
        if (rule.array && Array.isArray(sanitizedValue)) {
            const arrayResult = await this.validateArray(sanitizedValue, rule, fieldPath);
            if (!arrayResult.isValid) {
                errors.push(...arrayResult.errors);
            } else {
                sanitizedValue = arrayResult.sanitizedValue;
            }
        }

        // 对象验证
        if (rule.properties && typeof sanitizedValue === 'object' && sanitizedValue !== null) {
            const objectResult = await this.validateData(sanitizedValue, rule.properties, fieldPath);
            if (!objectResult.isValid) {
                errors.push(...objectResult.errors);
            } else if (this.options.sanitize) {
                sanitizedValue = objectResult.sanitizedData;
            }
        }

        // 自定义验证函数
        if (rule.validator && typeof rule.validator === 'function') {
            try {
                const customResult = await rule.validator(sanitizedValue, fieldPath);
                if (customResult !== true) {
                    errors.push(typeof customResult === 'string' ? customResult : `${fieldPath}: Custom validation failed`);
                }
            } catch (error) {
                errors.push(`${fieldPath}: Custom validation error`);
            }
        }

        // 数据清理
        if (this.options.sanitize && rule.sanitize && typeof rule.sanitize === 'function') {
            try {
                sanitizedValue = rule.sanitize(sanitizedValue);
            } catch (error) {
                console.warn(`[ValidationMiddleware] Sanitization error for ${fieldPath}:`, error);
            }
        }

        return {
            isValid: errors.length === 0,
            errors,
            sanitizedValue
        };
    }

    /**
     * 验证和转换类型
     * @param {*} value - 原始值
     * @param {Object} rule - 验证规则
     * @param {string} fieldPath - 字段路径
     * @returns {Object} 转换结果
     */
    validateAndConvertType(value, rule, fieldPath) {
        const errors = [];
        let convertedValue = value;

        if (!rule.type) {
            return { isValid: true, errors: [], convertedValue };
        }

        switch (rule.type) {
            case 'string':
                if (typeof value !== 'string') {
                    if (rule.coerce) {
                        convertedValue = String(value);
                    } else {
                        errors.push(`${fieldPath}: Must be a string`);
                    }
                }
                break;

            case 'number':
                if (typeof value !== 'number') {
                    if (rule.coerce) {
                        const parsed = Number(value);
                        if (isNaN(parsed)) {
                            errors.push(`${fieldPath}: Must be a valid number`);
                        } else {
                            convertedValue = parsed;
                        }
                    } else {
                        errors.push(`${fieldPath}: Must be a number`);
                    }
                }
                break;

            case 'boolean':
                if (typeof value !== 'boolean') {
                    if (rule.coerce) {
                        if (value === 'true' || value === '1' || value === 1) {
                            convertedValue = true;
                        } else if (value === 'false' || value === '0' || value === 0) {
                            convertedValue = false;
                        } else {
                            errors.push(`${fieldPath}: Must be a valid boolean`);
                        }
                    } else {
                        errors.push(`${fieldPath}: Must be a boolean`);
                    }
                }
                break;

            case 'array':
                if (!Array.isArray(value)) {
                    errors.push(`${fieldPath}: Must be an array`);
                }
                break;

            case 'object':
                if (typeof value !== 'object' || value === null || Array.isArray(value)) {
                    errors.push(`${fieldPath}: Must be an object`);
                }
                break;

            case 'date':
                if (!(value instanceof Date)) {
                    if (rule.coerce) {
                        const parsed = new Date(value);
                        if (isNaN(parsed.getTime())) {
                            errors.push(`${fieldPath}: Must be a valid date`);
                        } else {
                            convertedValue = parsed;
                        }
                    } else {
                        errors.push(`${fieldPath}: Must be a Date object`);
                    }
                }
                break;

            default:
                errors.push(`${fieldPath}: Unknown type '${rule.type}'`);
        }

        return {
            isValid: errors.length === 0,
            errors,
            convertedValue
        };
    }

    /**
     * 验证数组
     * @param {Array} array - 数组值
     * @param {Object} rule - 验证规则
     * @param {string} fieldPath - 字段路径
     * @returns {Object} 验证结果
     */
    async validateArray(array, rule, fieldPath) {
        const errors = [];
        const sanitizedArray = [];

        // 数组长度验证
        if (rule.minItems !== undefined && array.length < rule.minItems) {
            errors.push(`${fieldPath}: Must have at least ${rule.minItems} items`);
        }

        if (rule.maxItems !== undefined && array.length > rule.maxItems) {
            errors.push(`${fieldPath}: Must have no more than ${rule.maxItems} items`);
        }

        // 验证数组元素
        if (rule.items) {
            for (let i = 0; i < array.length; i++) {
                const itemResult = await this.validateField(array[i], rule.items, `${fieldPath}[${i}]`);
                if (!itemResult.isValid) {
                    errors.push(...itemResult.errors);
                } else if (this.options.sanitize) {
                    sanitizedArray[i] = itemResult.sanitizedValue;
                }
            }
        } else if (this.options.sanitize) {
            sanitizedArray.push(...array);
        }

        // 唯一性验证
        if (rule.unique) {
            const uniqueValues = new Set(array);
            if (uniqueValues.size !== array.length) {
                errors.push(`${fieldPath}: All items must be unique`);
            }
        }

        return {
            isValid: errors.length === 0,
            errors,
            sanitizedValue: this.options.sanitize ? sanitizedArray : array
        };
    }

    /**
     * 创建验证中间件
     * @param {Object} rules - 验证规则
     * @returns {Function} Express中间件函数
     */
    createValidationMiddleware(rules) {
        return (req, res, next) => {
            req.validationRules = rules;
            this.getMiddleware()(req, res, next);
        };
    }

    /**
     * 记录验证成功日志
     * @param {Request} req - Express请求对象
     */
    logValidationSuccess(req) {
        if (config.log.console && this.options.debug) {
            console.log(`[ValidationMiddleware][SUCCESS]`, {
                method: req.method,
                url: req.originalUrl,
                hasBody: !!req.body && Object.keys(req.body).length > 0,
                hasQuery: !!req.query && Object.keys(req.query).length > 0,
                timestamp: new Date().toISOString()
            });
        }
    }

    /**
     * 记录验证失败日志
     * @param {Request} req - Express请求对象
     * @param {Array} errors - 验证错误
     */
    logValidationFailure(req, errors) {
        if (config.log.console) {
            console.warn(`[ValidationMiddleware][FAILED]`, {
                method: req.method,
                url: req.originalUrl,
                errorCount: errors.length,
                errors: errors.slice(0, 5), // 只记录前5个错误
                ip: this.getClientIP(req),
                timestamp: new Date().toISOString()
            });
        }
    }

    /**
     * 添加自定义验证规则
     * @param {string} name - 规则名称
     * @param {Object} rule - 规则定义
     */
    addCommonRule(name, rule) {
        this.commonRules[name] = rule;
        console.log(`✓ Common validation rule '${name}' added`);
    }

    /**
     * 获取所有验证规则
     * @returns {Object} 验证规则
     */
    getCommonRules() {
        return { ...this.commonRules };
    }
}

// 创建默认实例
export const validationMiddleware = new ValidationMiddleware();

// 导出便捷方法
export const validate = (rules) => validationMiddleware.createValidationMiddleware(rules);

export default ValidationMiddleware;